using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace WCell.Core.Addons
{
	/// <summary>
	/// Contains all information related to an Addon.
	/// </summary>
	public class WCellAddonContext
	{
		protected WCellAddonDescriptor m_descriptor;
		protected Assembly m_assembly;
		protected IWCellAddon m_addon;

		public WCellAddonContext(WCellAddonDescriptor descriptor, bool autoLoad)
		{
			m_descriptor = descriptor;
			
			if (autoLoad)
			{
				Load();
			}

			WCellAddonMgr.AddContext(this);
		}

		/// <summary>
		/// The descriptor, holding the original filename and TypeName of the Assembly and its containing Addon
		/// </summary>
		public WCellAddonDescriptor Descriptor
		{
			get
			{
				return m_descriptor;
			}
		}

		/// <summary>
		/// The containing assembly (might be null if descriptor has not been loaded yet)
		/// </summary>
		public Assembly Assembly
		{
			get
			{
				return m_assembly;
			}
		}

		/// <summary>
		/// The created Addon (might be null if descriptor has not been loaded yet or if this a library which does not get initialized)
		/// </summary>
		public IWCellAddon Addon
		{
			get
			{
				return m_addon;
			}
		}

		/// <summary>
		/// Loads the Assembly and its addon (if not loaded already)
		/// </summary>
		/// <exception cref="ArgumentException">If the supplied Type does not exist in the Assembly that is in FilePath</exception>
		public void Load()
		{
			if (m_assembly != null)
			{
				return;
			}

		    m_assembly = Assembly.LoadFrom(m_descriptor.FilePath);

			// this will throw an Exception if loading failed
			var types = m_assembly.GetTypes();

			if (m_descriptor.TypeName != null)
			{
				var addonType = m_assembly.GetType(m_descriptor.TypeName, false, true);
				if (addonType == null)
				{
					foreach (var type in types)
					{
						if (type.FullName.Equals(m_descriptor.TypeName, StringComparison.InvariantCultureIgnoreCase))
						{
							addonType = type;
							break;
						}
					}
					if (addonType == null)
					{
						throw new Exception(string.Format("Addon Assembly \"{0}\" did not contain specified Type \"{1}\"",
							m_assembly, m_descriptor.TypeName));
					}
				}
				m_addon = Activator.CreateInstance(addonType) as IWCellAddon;
				if (m_addon == null)
				{
					throw new ArgumentException(m_descriptor.TypeName + " in Assembly " + m_assembly + " is not of type WCellAddon.");
				}

				if (m_addon.Config != null)
				{
					WCellAddonMgr.Configurations.Add(m_addon.Config);
				}

                if (WCellAddonMgr.Addons.ContainsKey(m_addon.ShortName))
                {
                    throw new ArgumentException(string.Format("Found more than one addon with Shortname \"{0}\": {1} and {2}", 
                        m_addon.ShortName,
                        WCellAddonMgr.GetAddon(m_addon.ShortName),
                        m_addon));
                }
				WCellAddonMgr.Addons.Add(m_addon.ShortName, m_addon);
			}
		}

		public override string ToString()
		{
			if (m_assembly == null)
			{
				return "AddonContext (not loaded) - " + m_descriptor;
			}
			if (m_addon == null) {
				return "AddonContext (loaded, no addon) - " + m_assembly.FullName;
			}
			return "AddonContext (loaded) - " + m_addon.GetDefaultDescription();
		}
	}
}
